#! /bin/bash
### BEGIN INIT INFO
# Provides:          lance_tool
# Required-Start:    $network $local_fs
# Required-Stop:     $network $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      1
# Short-Description: Start lance_tool
# Description: Start and Stop the lance_tool
### END INIT INFO
#
# Lance Tool
#
# chkconfig: 345 20 80
# description: Lance Tool
#
# /etc/rc.d/init.d/lance_*
# See how we were called.

PPTP_SERVER="lance.chn.hp.com"
PPTP_USER="lzxclient"
PPTP_PASSWD="showmethemoneyxa"

PPTP_LINK="LZXVPN"
PPTP_PIDF="/var/run/ppp-$PPTP_LINK.pid"

#=========================================================================
function get_proc_pid(){
    ps -elf | grep "`basename $0`" | grep background | grep -v grep | awk '{print $4}' | head -n 1
    return
}

function get_pptp_pid(){
  [ -r "$PPTP_PIDF" ] && cat "$PPTP_PIDF" | head -n 1
  return
}

function get_pptp_dev(){
  [ -r "$PPTP_PIDF" ] && cat "$PPTP_PIDF" | tail -n 1
  return
}

function get_pptp_local_ip(){
  [ ! -r "$PPTP_PIDF" ] && return
  ifconfig `get_pptp_dev`| grep "P-t-P" | head -n 1 | awk '{print $2}' | awk -F":" '{print $2}' | head -n 1
  return
}

function get_pptp_remote_ip(){
  [ ! -r "$PPTP_PIDF" ] && return
  ifconfig `get_pptp_dev`| grep "P-t-P" | head -n 1 | awk '{print $3}' | awk -F":" '{print $2}' | head -n 1
  return
}

function get_daemon_pid(){
    ps -elf | grep "`basename $0`" | grep background | grep -v grep | awk '{print $4}' | head -n 1
    return
}

function get_agent_default_dev(){
  route -n | awk '($1 == "0.0.0.0"){ print $NF}' | head -n 1
  return
}

function get_agent_default_gw(){
  route -n | awk '($1 == "0.0.0.0"){ print $2}' | head -n 1
  return
}

function get_agent_default_net(){
  route -n | awk 'BEGIN{ defdev = "" }{\
    if ($1 == "0.0.0.0") { defdev = $NF; }\
    if ( $NF == defdev && $2 == "0.0.0.0" && $4 == "U") { print $1; }\
  }' | head -n 1
  return
}

function get_agent_default_mask(){
  route -n | awk 'BEGIN{ defdev = "" }{\
    if ($1 == "0.0.0.0") { defdev = $NF; }\
    if ( $NF == defdev && $2 == "0.0.0.0" && $4 == "U") { print $3; }\
  }' | head -n 1
  return
}

#=========================================================================

function log_msg(){
  LOG_FILE="/var/log/`basename $0`.`hostname`.log"
  CONTENT="$1"
  TYPE="$2"

  echo "["`date +"%Y/%m/%d %H:%M:%S"`"]: ""$CONTENT" >> $LOG_FILE
  [ "$TYPE" == "2" ] && echo "$CONTENT"
  return 0
}

function add_chap_secrets(){
  CHAP_FILE="/etc/ppp/chap-secrets"
  [ ! -r"$CHAP_FILE" ] && return
  cat "$CHAP_FILE" 2>&1 | grep "$PPTP_USER" | grep "$PPTP_PASSWD" >/dev/null
  [ $? != 0 ] && echo "$PPTP_USER	* \"$PPTP_PASSWD\" *" >> "$CHAP_FILE"
  return
}

function wait_ppp_link_ready(){
  cnt=1
  while [ "`get_pptp_local_ip`" == "" ]
  do
    sleep 1
    let cnt=cnt+1
    [ $cnt -gt 30 ] && return
  done
  return
}

function run_on_remote(){
  SCR="/root/scripts/common/scr.exp"
  CMD="$1"

  log_msg "$PPTP_SERVER> $CMD"

  [ ! -r "$SCR" ] && return
  $SCR iforgotla root@$PPTP_SERVER "/root" "$CMD" | awk '\
  BEGIN{ \
    PRT=0;\
  }{\
    if ( PRT >= 1 ) { PRT = PRT + 1; }\
    if ( $0 ~ /root@.*\:\~\# cd \/root/ ) { PRT=1; }\
    if ( $0 ~ /root@.*\:\~\# exit/) { PRT=0; }\
    if ( PRT >= 3 ) { print $0; }\
  }' 
  return
}

function find_remote_ppp_dev(){
  agt_dev="`get_pptp_dev`"
  agt_loc_ip="`get_pptp_local_ip`"
  agt_rmt_ip="`get_pptp_remote_ip`"

  [ "$agt_dev" == "" ] && return
  [ "$agt_loc_ip" == "" ] && return
  [ "$agt_rmt_ip" == "" ] && return

  # The loc_ip and rmt_ip shall be reversed on remote server
  run_on_remote "ifconfig" | awk 'BEGIN{ ppp_dev="" }{\
    if ($0 ~ /ppp.*Link encap:Point-to-Point Protocol/){ ppp_dev = $1; }\
    if ( $1 = "inet" && $2 ~ /addr:.*/ && $3 ~ /P-t-P:.*/) { \
      gsub("addr:", "", $2);\
      gsub("P-t-P:", "", $3);\
      print ppp_dev, $2, $3; \
    }\
  }' | while read svr_dev svr_loc_ip svr_rmt_ip
  do
    [ "$svr_loc_ip" == "$agt_rmt_ip" -a "$svr_rmt_ip" == "$agt_loc_ip" ] && echo $svr_dev
  done | head -n 1
  return
}

function setup_remote_ppp_route(){
  remote_ppp_dev="`find_remote_ppp_dev`"
  agent_net="`get_agent_default_net`"
  agent_mask="`get_agent_default_mask`"
  agent_addr="`get_pptp_local_ip`"

  [ "$remote_ppp_dev" == "" ] && return
  [ "$agent_net" == "" ] && return
  [ "$agent_mask" == "" ] && return
  [ "$agent_addr" == "" ] && return

  ACTION="$1"
  log_msg "Setup $PPTP_SERVER 's iptables, $ACTION......" 2

  # iptables NAT forwarding
  rulnum=`run_on_remote "iptables -t nat -L POSTROUTING --line-numbers" | \
          grep "$agent_net" | awk '{print $1}'`
  [ "$rulnum" != "" ] && run_on_remote "iptables -t nat -D POSTROUTING $rulnum"
  # Only for disconnect, we need to purge iptable rules on the server
  # Route was not required to clean, since the server will clean by itself
  [ "$ACTION" == "erase" ] && return

  run_on_remote "iptables -d $agent_net/$agent_mask -o $remote_ppp_dev -t nat -A POSTROUTING -j MASQUERADE"

  log_msg "Setup $PPTP_SERVER 's routing, $ACTION......" 2
  # server default route
  run_on_remote "route del -net $agent_net netmask $agent_mask 1>/dev/null  2>&1"
  run_on_remote "route add -net $agent_net netmask $agent_mask gw $agent_addr device $remote_ppp_dev"
  return
}

#=========================================================================
function ppp_connect()
{
  add_chap_secrets

  [ -r "$PPTP_PIDF" ] && log_msg "PPP pid exists, abort connecting" 2 && return


  log_msg "Calling /usr/sbin/pppd to connect pptp server: $PPTP_SERVER" 2
  /usr/sbin/pppd\
    pty "pptp $PPTP_SERVER --nolaunchpppd" \
    lock \
    noauth \
    nobsdcomp \
    nodeflate \
    name "$PPTP_USER" \
    password "$PPTP_PASSWD" \
    linkname "$PPTP_LINK" \
    remotename "$PPTP_LINK" \
    ipparam "$PPTP_LINK" \
    require-mppe-128

  log_msg "Waiting ppp link to be ready ......" 2
  wait_ppp_link_ready

  log_msg "Establish PPP connect with PID=`get_pptp_pid`, DEV=`get_pptp_dev`" 2

  setup_remote_ppp_route build
  return
}

function ppp_disconnect()
{
  if [ -r "$PPTP_PIDF" ]
  then
    log_msg "Terminiate PPP link with PID=`get_pptp_pid`, DEV=`get_pptp_dev`" 2

    setup_remote_ppp_route erase

    kill -INT `get_pptp_pid`
    if [ ! $? == 0 ]
    then
      rm -rf "$PPTP_PIDF"
      log_msg "ERROR: Removed stale pid file" 2
    fi
  fi
  return
}

function ppp_check_connect()
{
  # Interface test
  itf_test=`get_pptp_dev`
  if [ "$itf_test" == "" ]
  then
    log_msg "ERROR: VPN interface not found ......" 2
    ppp_disconnect
    ppp_connect
    return
  fi

  # Remote Addr test
  remote_addr=`get_pptp_remote_ip`
  if [ "$remote_addr" == "" ]
  then
    log_msg "ERROR: VPN remote address not found ......" 2
    ppp_disconnect
    ppp_connect
    return
  fi
    
  # Link Test
  link_test=$(ping -c 3 "$remote_addr" | grep "time=")
  if [ "$link_test" == "" ]
  then
    log_msg "ERROR: VPN Gateway is offline ......" 2
    ppp_disconnect
    ppp_connect
    return
  fi

  #echo "ppp_check_connect finished, ALL OK"
  return
}

function ppp_auto_connect()
{
  while [ 1 ]
  do
    ppp_check_connect
    sleep 30
  done
  return
}

function ppp_status(){
    echo "`basename $0` Daemon Process [`get_daemon_pid`]"
    echo ""
    echo "`basename $0` Default Ethernet Device [`get_agent_default_dev`]"
    echo "  - ETH Default Net : `get_agent_default_net`"
    echo "  - ETH Default Mask: `get_agent_default_mask`"
    echo "  - ETH Default GW  : `get_agent_default_gw`"
    echo ""
    echo "`basename $0` PPTP Link Process [`get_pptp_pid`]"
    echo "  - PPP Server Addr : $PPTP_SERVER"
    echo "  - PPP Device      : `get_pptp_dev`"
    echo "  - PPP Local IP    : `get_pptp_local_ip`"
    echo "  - PPP Remote IP   : `get_pptp_remote_ip`"
    echo ""
    echo "$PPTP_SERVER Peer PPP Device [`find_remote_ppp_dev`]"
    defnet=`get_agent_default_net`
    [ "$defnet" != "" ] && \
      rmtdev=`run_on_remote "route -n"| \
              awk '( $1 == "'"$defnet"'"){ print $NF}' |\
              head -n 1 | tr -d "\r"`
    [ "$defnet" != "" ] && \
      natdev=`run_on_remote "iptables -t nat -L POSTROUTING -v" | \
              grep "$defnet" | awk '{print $7}' | tr -d "\r"`
    echo "  - Routing to [$defnet] over [$rmtdev]"
    echo "  - NAT POSTROUTING to [$defnet] over [$natdev]"
    exit 0
}

#=========================================================================
case "$1" in
    start)
        nohup $0 background >/dev/null 2>&1 &
        wait_ppp_link_ready
        echo "Started `basename $0` [`get_proc_pid`]"
        exit 0
    ;;

    stop)
        PID=`get_proc_pid`
        ppp_disconnect
        if [ "$PID" != "" ]
        then
            kill -s 9 $PID
            log_msg "Stopped `basename $0` [$PID]" 2
        else
            log_msg "Nothing to do." 2
        fi
        exit 0
    ;;

    restart)
        $0 stop
        $0 start
        exit 0
    ;;
    

    test)
        echo "Just a test ......"
        exit 0
    ;;

    connect)
        ppp_connect
        exit 0
    ;;

    disconnect)
        ppp_disconnect
        exit 0
    ;;

    status)
        ppp_status
        exit 0
    ;;

    background)
        ppp_auto_connect
        exit 0
    ;;

    install)
        echo "Unimplemented......"
        exit 0
    ;;

    *)
        echo "Usage: /etc/init.d/`basename $0` {start|stop|restart|status}"
        exit 1
    ;;
esac


